from moviepy.editor import *
from PIL import Image, ImageSequence
# from azure import azure_speech
from moviepy.editor import concatenate_videoclips, AudioFileClip, CompositeAudioClip, ImageClip
from datetime import datetime
from config.configBusiness import ai_make_config  # 导入 AiMake 类的实例对象
from config.template import get_all_to_url, template_config, get_list_gif, get_list_gif_2, get_list_png_time, \
    select_by_model_id, \
    get_list_music_time
import random
import numpy as np
from https.UploadPaths import upload_file, UploadPaths, list_files_temp_to_delete
from service.Impl import videoServiceImpl
from service import videoService
from jdk.tengxun.file_services import put_tencent_file
import log.logger as log


def gif_to_clip(gif):
    wGif = int(gif.get("wGif"))
    hGif = int(gif.get("hGif"))
    scale_w = ai_make_config.scales_gif['w']
    scale_h = ai_make_config.scales_gif['h']
    angleGif = gif.get("angleGif")

    gif_open = Image.open(extract_path(gif.get("url")))
    frames = []
    for frame in ImageSequence.Iterator(gif_open):
        frame = frame.convert('RGBA')
        frame = frame.rotate(-angleGif, expand=True)  # 以指定角度旋转图像
        frame = frame.resize((round(wGif * scale_w), round(hGif * scale_h)),
                             resample=Image.HAMMING)  # 使用 Image.BILINEAR 滤波器
        frames.append(np.array(frame))
    clip = ImageSequenceClip(frames, fps=25)
    return clip


def create_audio(content, music_param, use_speech=False):
    bg_music = AudioFileClip(music_param).volumex(0.8)
    if use_speech:
        speaker = 'zh-CN-XiaoxiaoNeural'
        output_file = "static/speech/test.mp3"
        # azure_speech.text2speech(content, speaker, output_file)
        # content_speech = AudioFileClip(output_file)
        content_speech = None
        audio = CompositeAudioClip([content_speech, bg_music])
    else:
        audio = bg_music
    return audio


def create_text(text_params, display_time):
    # 从样式中提取字体大小
    text_clips = []
    for text_param in text_params:
        content_text = create_content(text_param)
        content_font_size = get_control_to_font_size(text_param)
        content_text_color = get_control_to_text_color(text_param)
        content_text_align = get_control_to_text_align(text_param)
        control_to_text_stroke_width = get_control_to_text_stroke_width(text_param)
        control_to_text_stroke_color = get_control_to_text_stroke_color(text_param)
        content_text_rotate = get_control_to_text_rotate(text_param)
        content_text_font = get_control_to_text_font(text_param)
        x = text_param.get("xText")
        y = text_param.get("yText")
        # 设置文本显示的位置（x, y）
        scale_x = ai_make_config.scales_text['x']
        scale_y = ai_make_config.scales_text['y']
        text_position = (float(x) * scale_x, float(y) * scale_y)
        text_position = tuple(int(value) for value in text_position)
        # 创建文本剪辑，设定文本内容、字体大小、颜色、字体、对齐方式、描边、持续时间、位置
        text_clip = TextClip(content_text,
                             fontsize=int(content_font_size),  # 字体大小
                             color=content_text_color,  # 文本颜色
                             font=content_text_font,  # 字体文件路径
                             align=content_text_align,  # 文本对齐方式
                             stroke_width=control_to_text_stroke_width,  # 描边宽度
                             stroke_color=control_to_text_stroke_color  # 描边颜色
                             ).set_duration(display_time).set_position(text_position).rotate(
            -content_text_rotate)  # 持续时间和位置

        text_clips.append(text_clip)
    return text_clips


if __name__ == '__main__':
    input_dir = "static/ai/ai_01/mate"
    output_dir = "static/ai/ai_01/out"
    txt_list = ["理智","你就是有大病","OUT","就很棒","改哪"]
    for filename in os.listdir(input_dir):
        if filename.endswith(".png") or filename.endswith(".jpg"):  # 过滤图片文件
            selected_text = random.choice(txt_list)
            # 创建带有描边的文本
            text_clip = TextClip(
                selected_text,
                fontsize=90,  # 字体大小
                color="white",  # 文本颜色
                font="static/font/110159_MaoKenShiJinHei-2.ttf",  # 字体文件路径
                stroke_color="black",  # 描边颜色
                align='center',
                stroke_width=5  # 描边宽度（确保没有描边）
            ).set_position((random.randint(0, 300), random.randint(0, 300)))
            # 加载图片
            image_clip = ImageClip(os.path.join(input_dir, filename))
            # 将文本叠加到图片上
            result = CompositeVideoClip([image_clip.set_duration(1), text_clip.set_duration(1)])

            # 保存修改后的图片
            output_path = os.path.join(output_dir, filename)
            result.save_frame(output_path, t=0)

            print(f"Processed {filename} and saved to {output_path}")


def extract_path(url):
    if url and isinstance(url, str):
        index = url.find('static')
        if index != -1:
            new_url = url[index:]
        return new_url
    else:
        # 处理 music_file 为空的情况，可以返回默认值或者执行相应的逻辑
        return None  # 你可以根据需要返回适当的默认值或执行其他逻


def get_control_to_text_stroke_color(text_param):
    default_stroke_color = 'black'  # 默认文本描边颜色

    return text_param.get('stroke', default_stroke_color)


def get_control_to_text_rotate(text_param):
    default_rotation_angle = 0
    rotation_angle = text_param.get('angleText', default_rotation_angle)  # 获取 rotationAngle 属性，如果不存在则默认为 0

    # 尝试将 rotation_angle 转换为整数类型，并返回结果
    try:
        return int(rotation_angle)
    except (ValueError, TypeError):
        return default_rotation_angle  # 如果无法转换为整数或不是数字类型，则返回默认值


def get_control_to_text_font(text_param):
    text_font_key = text_param.get('selectedFont')
    font = ai_make_config.fonts[text_font_key]
    return font


def get_control_to_text_stroke_width(text_param):
    default_stroke_width = 1  # 默认文本描边宽度

    return text_param.get('stroke_width', default_stroke_width)


def get_control_to_text_align(text_param):
    default_align = 'west'  # 默认文本对齐方式

    return text_param.get('align', default_align)


def get_control_to_text_color(text_param):
    default_color = 'black'  # 默认文本颜色
    return text_param.get('color', default_color)


def get_control_to_font_size(text_param):
    font_size = text_param.get('fontSize', 60)  # 获取 fontSize 属性，如果不存在则默认为 60

    # 尝试将 font_size 转换为整数，并乘以 3 返回
    try:
        scale_font_size = ai_make_config.scales_text['font_size']
        font_size_value = int(font_size) * scale_font_size
        return font_size_value
    except (ValueError, TypeError):
        return font_size  # 如果无法转换为整数或不是数字类型，则直接返回原始值


def create_anim(gifs_params):
    gif_clips = [gif_to_clip(gif) for gif in gifs_params]
    gif_clips_new = []
    scale_x = ai_make_config.scales_gif['x']
    scale_y = ai_make_config.scales_gif['y']
    for gif, params in zip(gif_clips, gifs_params):
        x_gif = params.get('xGif', 0)
        y_gif = params.get('yGif', 0)
        gif_with_position = gif.set_position((round(x_gif * scale_x, 6), round(y_gif * scale_y, 6)))
        gif_clips_new.append(gif_with_position)

    return gif_clips_new


def create_content(text_param):
    html_text = text_param.get('HTMLText')
    # 替换 <br> 为换行符 \n
    html_text = html_text.replace('<br>', '\n')

    # 替换 &nbsp; 为普通空格
    html_text = html_text.replace('&nbsp;', ' ')

    return html_text


def create_video(text_params, gifs_params, png_param, music_param):
    try:
        # content = create_content(textParam)
        # content 可以转换为语音
        music_clips = create_audio(None, music_param)
        gif_clips = create_anim(gifs_params)
        # 暂时使用gif时长为视频时长
        # video_time = gif_clips.duration
        video_time = 6
        text_clips = create_text(text_params, video_time)
        bkgd_clips = videoServiceImpl.get_background_path_to_clip(video_time, png_param)

        # 创建一个空的 CompositeVideoClip
        # 将 background 放在列表的第一个位置
        final_clips = [bkgd_clips] + gif_clips + text_clips
        final_clip = CompositeVideoClip(final_clips)

        # 将动画剪辑添加到 final_clip 中
        # for gif_clip in gif_clips:
        #    final_clip = CompositeVideoClip([final_clip, gif_clip])

        final_clip = final_clip.set_audio(music_clips)

        current_time = datetime.now().strftime("%Y%m%d%H%M%S")
        output_path = f"static/video_output/define/output_{current_time}.mp4"
        final_clip.set_duration(video_time).write_videofile(output_path, codec='libx264')
        return output_path  # 返回视频文件路径
    except Exception as e:
        return str(e)  # 返回异常信息给前端


def video_template(template_id, lower=None, retries=0):
    if retries >= 10:
        print("<< 达到最大重试次数，操作中止。")
        return {"code": -1, "data": "达到最大重试次数。"}
    upload_paths = UploadPaths()
    upload_folder = upload_paths.get_path("temp")
    if not lower:
        template_id = int(template_id)
    templ_parm = template_config.template_id[template_id]
    # 获取所有的文案
    list_text = select_by_model_id(template_id, get_all_to_url(template_config.bqb_writing))
    # 获取所有表情
    list_gif = get_list_gif(get_all_to_url(template_config.bqb_look))
    list_gif_2 = get_list_gif_2("https://bqb.kaixinchuichui.cn/api/bqb/erchuang?day=10")
    # 获取所有背景
    # get_list_png_time 日期筛选
    list_png = get_list_png_time(get_all_to_url(template_config.bqb_back))
    # 获取所有音乐
    list_music = get_list_music_time(get_all_to_url(template_config.bqb_music))
    # 获取所有头像
    list_avatar = get_all_to_url(template_config.bqb_virtually)
    # 获取所有字体
    list_typeface = get_all_to_url(template_config.bqb_typeface)
    log.log_put(7, template_id, None)
    try:
        final_clip = None
        total_duration = None
        audio_clip = None
        text_parm = None
        selected_avatars = None
        if template_id == 51:
            # templ_parm = templ_parm[random_key]
            templ_parm = templ_parm[lower]
            # TODO 视频程度随机
            templ_parm['time_len'] = random.randint(9, 15)
            final_clip, audio_clip, total_duration, selected_gifs, selected_png, selected_music = videoService.template_id_51(
                templ_parm, list_gif, list_gif_2, list_png,
                list_music, upload_folder, lower)
        elif template_id == 4:
            text_parm, final_clip, audio_clip, total_duration, selected_gifs, selected_png, selected_music = videoService.template_id_4(
                template_id, templ_parm, list_gif, list_text,
                list_music, upload_folder, list_typeface)
        elif template_id == 16:
            text_parm, final_clip, audio_clip, total_duration, selected_gifs, selected_png, selected_music = videoService.template_id_16(
                templ_parm, list_gif, list_png, list_text, list_music, upload_folder, list_typeface)
        elif template_id == 54:
            text_parm, final_clip, audio_clip, total_duration, selected_gifs, selected_png, selected_music, selected_avatars = videoService.template_id_54(
                templ_parm, list_gif, list_png, list_text,
                list_music, list_avatar, list_typeface, upload_folder)
        elif template_id == 47:
            text_parm, final_clip, audio_clip, total_duration, selected_gifs, selected_png, selected_music = videoService.template_id_47(
                template_id, templ_parm, list_gif, list_music, list_typeface, upload_folder)
        elif template_id == 48:
            text_parm, final_clip, audio_clip, total_duration, selected_gifs, selected_png, selected_music = videoService.template_id_48(
                template_id, templ_parm, list_gif,list_gif_2, list_music, upload_folder)
        elif template_id == 49:
            text_parm, final_clip, audio_clip, total_duration, selected_gifs, selected_png, selected_music = videoService.template_id_49(
                template_id, templ_parm,list_gif_2, list_music, upload_folder)
        else:
            log.log_put(18, template_id, None)
            return
        log.log_put(8, template_id, None)
        # 将音频添加到视频中
        final_clip = final_clip.set_audio(audio_clip)
        # 输出最终视频文件
        current_time = datetime.now().strftime("%Y%m%d%H%M%S")
        # 备份至本地 >>> 不保留可注释下面这行
        upload_folder = upload_paths.get_path("out")
        if template_id == 51:
            output_path = f"{upload_folder}/{template_id}/{lower}"
        else:
            output_path = f"{upload_folder}/{template_id}"
        log.log_put(9, None, None)

        # 没有文件夹就创建
        if not os.path.exists(output_path):
            os.makedirs(output_path)
        output_path += f"/output_{current_time}.MOV"
        final_clip.set_duration(total_duration).write_videofile(output_path, codec='libx264', fps=24)
        log.log_put(10, None, None)
        # 上传文件服务器
        # data_dict = put_tencent_file(text_parm, template_id, output_path, upload_folder, selected_gifs, selected_png,
        #                        selected_music, selected_avatars)
        return output_path
    except Exception as e:
        print(f"<< 合成失败，准备重试，原因： {e}")
        return video_template(template_id, lower, retries=retries + 1)
    finally:
        # 删除的文件列表
        list_files_temp_to_delete("temp", os.getcwd())

